package com.jiaai.cloud.base.redis.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.*;

import java.util.Map;
import java.util.Set;

public class RedisUtil {

	public RedisUtil(){}

	private Logger logger= LoggerFactory.getLogger(RedisUtil.class);
	/**
	 * redis 连接池
	 */
	private static JedisPool jedisPool;
	private JedisPoolConfig defaultConfig(){
			JedisPoolConfig config = new JedisPoolConfig();
			config.setMaxTotal(200);
			config.setMaxIdle(50);
			config.setMinIdle(8);//设置最小空闲数
			config.setMaxWaitMillis(10000);
			config.setTestOnBorrow(true);
			config.setTestOnReturn(true);
			//Idle时进行连接扫描
			config.setTestWhileIdle(true);
			//表示idle object evitor两次扫描之间要sleep的毫秒数
			config.setTimeBetweenEvictionRunsMillis(30000);
			//表示idle object evitor每次扫描的最多的对象数
			config.setNumTestsPerEvictionRun(10);
			//表示一个对象至少停留在idle状态的最短时间，然后才能被idle object evitor扫描并驱逐；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
			config.setMinEvictableIdleTimeMillis(60000);
			return config;
		
	}
	public RedisUtil(JedisPool jedisPool){
		if(logger.isDebugEnabled()){
			logger.debug("初始化Redis工具類");
		}
		this.jedisPool =jedisPool;
	}
	public RedisUtil(JedisPoolConfig config, String host, int port, int timeout){
			if(logger.isDebugEnabled()){
				logger.debug("初始化Redis工具類");
			}
			jedisPool =new JedisPool(config, host, port, timeout);
	}
	
	public RedisUtil(String host, int port, int timeout){
			jedisPool =new JedisPool(defaultConfig(), host, port, timeout);
	}
	
	/**
	 * 保证在执行操作之后释放数据源returnResource(jedis)
	 */
	abstract class Executor<T> {

		int dbIndex=0;
		Jedis jedis;//非切片额客户端连接
		JedisPool jedisPool;
		public Executor(JedisPool jedisPool, Integer dbIndex) {
			this.jedisPool = jedisPool;
			this.jedis=this.jedisPool.getResource();
			this.dbIndex=dbIndex;
			
		}

		/**
		 * 回调
		 * @return 执行结果
		 */
		abstract T execute();
		
		/**
		 * 调用{@link #execute()}并返回执行结果
		 * @return 执行结果
		 */
		public T getResult() {
			T result = null;
			try {
				
				jedis.select(dbIndex);
				result = execute();
			} catch (Throwable e) {
				throw new RuntimeException("Redis execute com.jiai.cloud.base.core.exception", e);
			} finally {
				 jedis.close();
			}
			return result;
		}
	}

	/**
	 * 模糊匹配得到value值
	 * @param dbIndex
	 * @param key
	 * @return
	 */
	public Set<String> getKey(int dbIndex, final String key) {
		return new Executor<Set<String>>(jedisPool,dbIndex) {
			@Override
			Set<String> execute() {
				return jedis.keys(key);
			}
		}.getResult();


	}
	/**
	 * 刪除所有匹配的key
	 * @return
	 */
	public Boolean delKey(int dbIndex,final byte[]... keys) {
		return new Executor<Boolean>(jedisPool,dbIndex) {
			@Override
			Boolean execute() {
				try {
					  Pipeline pipeline=jedis.pipelined();
						for (byte[] key : keys) {
							pipeline.del(key);
						}
						pipeline.sync();
						return true;
				} catch (Exception e) {
						return false;
				}
			}
		}.getResult();
	}
	/**
	 * 刪除所有匹配的key

	 * @return
	 */
	public Boolean delKey(int dbIndex,final String... keys) {
		return new Executor<Boolean>(jedisPool,dbIndex) {
			@Override
			Boolean execute() {
				try {
					  Pipeline pipeline=jedis.pipelined();
						for (String key : keys) {
							pipeline.del(key);
						}
						pipeline.sync();
						return true;
				} catch (Exception e) {
						return false;
				}
			}
		}.getResult();
	}
	
	/**
	 *保存字符串并设置有效时间
	 * @param dbIndex 数据库索引
	 * @param key  键
	 * @param value 值 
	 * @param expire 设置过期时间
	 */
	public String  set(int dbIndex,final String key,final String value,final int expire) {
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				return jedis.setex(key, expire, value);
			}
		}.getResult();
		
		
	}
	/**
	 * 保存字符串
	 * @param dbIndex 数据库索引
	 * @param key   键
	 * @param value  值 
	 * @return
	 */
	public String set(int dbIndex,final String key,final String value) {		
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				return jedis.set(key, value);
			}
		}.getResult();
	}
	
	/**
	 * 序列化对像并设置过期时间
	 * @param dbIndex 数据库索引
	 * @param key 键
	 * @param value 值 
	 * @param expire 设置过期时间
	 * @return
	 */
	public String set(int dbIndex,final String key,final Object value, final int expire) {
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				return jedis.setex(key.getBytes(),expire, SerializationUtils.serialize(value));
			}
		}.getResult();
		
	}
	
	/**
	 * 序列化对像
	 * @param dbIndex 数据库索引
	 * @param key  键
	 * @param value 值 
	 * @return
	 */
	public String set(int dbIndex,final String key,final Object value) {
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				return jedis.set(key.getBytes(), SerializationUtils.serialize(value));
			}
		}.getResult();
	}
	
	
	
	/***
	 * 查询指定key 并返回二进制数据
	 * @param dbIndex
	 * @param key
	 * @return
	 */
	public byte[] getByte(int dbIndex,final String key){
		return new Executor<byte[]>(jedisPool,dbIndex) {
			@Override
			byte[] execute() {
				return jedis.get(key.getBytes());
			}
		}.getResult();
	}
	
	/**
	 * 查询指定key的值
	 * @param dbIndex
	 * @param key
	 * @return
	 */
	public String getString(int dbIndex,final String key){
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				return jedis.get(key);
			}
		}.getResult();
	}
	
	
   
	
	
	/**
	 * 设置key过期时间
	 * @param dbIndex
	 * @param key
	 * @param expire
	 * @return
	 */
	public Long expire(int dbIndex,final String key, final int expire){
		return new Executor<Long>(jedisPool,dbIndex) {
			@Override
			Long execute() {
				return jedis.expire(key,expire);
			}
		}.getResult();
	}
	
	/**
	 * 设置key过期时间
	 * @param dbIndex
	 * @param key
	 * @param expire
	 * @return
	 */
	public Long expire(int dbIndex,final byte[] key, final int expire){
		return new Executor<Long>(jedisPool,dbIndex) {
			@Override
			Long execute() {
				return jedis.expire(key,expire);
			}
		}.getResult();
	}
	
	
	/**
	 * 返回哈希表 key 中给定域 field 的值。 如果哈希表 key 存在，同时设置这个 key 的生存时间
	 * @param dbIndex
	 * @param key key
	 * @param field 域
	 * @param expire 生命周期，单位为秒
	 * @return 给定域的值。当给定域不存在或是给定 key 不存在时，返回 nil 。
	 */
	public String hashGet(int dbIndex, final String key, final String field, final int expire) {
		return new Executor<String>(jedisPool,dbIndex) {

			@Override
			String execute() {
				Pipeline pipeline =jedis.pipelined();
				Response<String> result = pipeline.hget(key, field);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}
	
	/**
	 * 返回哈希表 key 中给定域 field 的值。 如果哈希表 key 存在
	 * @param dbIndex
	 * @param key key
	 * @param field 域
	 * @return 给定域的值。当给定域不存在或是给定 key 不存在时，返回 nil 。
	 */
	public String hashGet(int dbIndex, final String key, final String  field) {
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				return jedis.hget(key, field);
			}
		}.getResult();
	}
	/**
	 * 返回哈希表 key 中给定域 field 的值。 如果哈希表 key 存在
	 * @param dbIndex
	 * @param key key
	 * @param field 域
	 * @return 给定域的值。当给定域不存在或是给定 key 不存在时，返回 nil 。
	 */
	public byte[] hashGet(int dbIndex, final byte[] key, final byte[] field) {
		return new Executor<byte[]>(jedisPool,dbIndex) {
			@Override
			byte[] execute() {
				return jedis.hget(key, field);
			}
		}.getResult();
	}
	/**
	 * 返回哈希表 key 中给定域 field 的值。 如果哈希表 key 存在，同时设置这个 key 的生存时间
	 * @param dbIndex
	 * @param key key
	 * @param field 域
	 * @param expire 生命周期，单位为秒
	 * @return 给定域的值。当给定域不存在或是给定 key 不存在时，返回 nil 。
	 */
	public byte[] hashGet(int dbIndex, final byte[] key, final byte[] field, final int expire) {
		return new Executor<byte[]>(jedisPool,dbIndex) {
			@Override
			byte[] execute() {
				Pipeline pipeline =jedis.pipelined();
				
				Response<byte[]> result = pipeline.hget(key, field);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}
	/**
	 * 将哈希表 key 中的域 field 的值设为 value 。
	 * 如果 key 不存在，一个新的哈希表被创建并进行 hashSet 操作。
	 * 如果域 field 已经存在于哈希表中，旧值将被覆盖。
	 * @params dbIndex 
	 * @param key key
	 * @param field 域
	 * @param value string value
	 * @return 如果 field 是哈希表中的一个新建域，并且值设置成功，返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖，返回 0 。
	 */
	public Long hashSet(int dbIndex, final String key, final String field, final String value) {
		return new Executor<Long>(jedisPool,dbIndex) {
			@Override
			Long execute() {
				return jedis.hset(key, field, value);
			}
		}.getResult();
	}
	/**
	 * 将哈希表 key 中的域 field 的值设为 value 。
	 * 如果 key 不存在，一个新的哈希表被创建并进行 hashSet 操作。
	 * 如果域 field 已经存在于哈希表中，旧值将被覆盖。
	 * @params dbIndex 
	 * @param key key
	 * @param field 域
	 * @param value string value
	 * @param expire 生命周期，单位为秒
	 * @return 如果 field 是哈希表中的一个新建域，并且值设置成功，返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖，返回 0 。
	 */
	public Long hashSet(int dbIndex, final String key, final String field, final String value, final int expire) {
		return new Executor<Long>(jedisPool,dbIndex) {
			@Override
			Long execute() {
				Pipeline pipeline = jedis.pipelined();
				Response<Long> result = pipeline.hset(key, field, value);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}
	/**
	 * 将哈希表 key 中的域 field 的值设为 value 。
	 * 如果 key 不存在，一个新的哈希表被创建并进行 hashSet 操作。
	 * 如果域 field 已经存在于哈希表中，旧值将被覆盖。
	 * @params dbIndex
	 * @param key key
	 * @param field 域
	 * @param value string value
	 * @return 如果 field 是哈希表中的一个新建域，并且值设置成功，返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖，返回 0 。
	 */
	public Long hashSet(int dbIndex,final byte[] key, final byte[] field, final byte[] value) {
		return new Executor<Long>(jedisPool,dbIndex) {
			@Override
			Long execute() {
				return jedis.hset(key, field, value);
			}
		}.getResult();
	}

	/**
	 *返回所有的field和值
	 * @params dbIndex
	 * @param key key
	 */
	public Map<byte[],byte[]> hashGetAll(int dbIndex, final byte[] key) {
		return new Executor< Map<byte[],byte[]>>(jedisPool,dbIndex) {
			@Override
			Map<byte[],byte[]> execute() {
				return jedis.hgetAll(key);
			}
		}.getResult();
	}
	/**
	 *返回所有的field和值
	 * @params dbIndex
	 * @param key key
	 */
	public Map<String,String> hashGetAll(int dbIndex, final String key) {
		return new Executor<Map<String,String>>(jedisPool,dbIndex) {
			@Override
			Map<String,String> execute() {
				return jedis.hgetAll(key);
			}
		}.getResult();
	}
	/**
	 * 将哈希表 key 中的域 field 的值设为 value 。
	 * 如果 key 不存在，一个新的哈希表被创建并进行 hashSet 操作。
	 * 如果域 field 已经存在于哈希表中，旧值将被覆盖。
	 * @params dbIndex 
	 * @param key key
	 * @param field 域
	 * @param value string value
	 * @param expire 生命周期，单位为秒
	 * @return 如果 field 是哈希表中的一个新建域，并且值设置成功，返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖，返回 0 。
	 */
	public Long hashSet(int dbIndex,final byte[] key, final byte[] field, final byte[] value,final int expire) {
		return new Executor<Long>(jedisPool,dbIndex) {
			@Override
			Long execute() {
				Pipeline pipeline = jedis.pipelined();
				Response<Long> result = pipeline.hset(key, field, value);
				pipeline.expire(key, expire);
				pipeline.sync();
				return result.get();
			}
		}.getResult();
	}
	
	/**
	 * 刪除一個map中多個值
	 * @param key
	 * @param fields
	 * @return
	 */
	public String hashDel(int dbIndex,final String key,final String... fields){
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				Pipeline pipeline = jedis.pipelined();
				for (String  field: fields) {
					pipeline.hdel(key, field);
				}
				pipeline.sync();
				return "";
			}
		}.getResult();
		
	}
	/**
	 * 刪除一個map中多個值
	 * @param key
	 * @param fields
	 * @return
	 */
	public String hashDel(int dbIndex,final byte[] key,final byte[]... fields){
		return new Executor<String>(jedisPool,dbIndex) {
			@Override
			String execute() {
				Pipeline pipeline = jedis.pipelined();
				for (byte[]  field: fields) {
					pipeline.hdel(key, field);
				
				}
				pipeline.sync();
				return "";
			}
		}.getResult();
		
	}
	
	//--------------get set-----------------
	public void setJedisPool(JedisPool jedisPool) {
		this.jedisPool = jedisPool;
	}
	
		
		
		
		
	
}
